using System;
using System.Collections;
using System.Collections.Generic;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using Nsb.Classes;
using jQueryApi;

namespace Yoshi.Classes
{
    [IgnoreNamespace]
    public class DropMenu
    {
        protected readonly jQueryObject FireButton;
        protected readonly jQueryObject List;
        protected readonly jQueryObject MenuWidget;
        protected jQueryObject ClickItem;

        public DropMenu(jQueryObject el, Dictionary nameList, ControlEventDelegate handler)
        {
            if (!Script.IsValue(nameList) || el == null || el.Length == 0)
            {
#if DEBUG
                Script.Literal("debugger");
#endif
                throw new Exception(Exceptions.ArgumentNull);
            }

            jQueryObject priorList = el.Prev(".DropMenu");
            if (priorList.Length == 0)
            {
                if (nameList.Count == 0)
                    return;

                MenuWidget = jQuery.FromHtml("<div class='DropMenuWidget' style='position:absolute'/>");
                new Await()
                    .AddDx(delegate
                           {
                               jQueryPosition p = el.Position();
                               MenuWidget.CSS(new Dictionary("top", p.Top, "left", p.Left + el.GetOuterWidth(), "margin-top", el.GetCSS("margin-top")));
                           })
                    .Commit();

                // The list fire drop down button
                FireButton = jQuery.FromHtml("<span class='DropMenuFire'/>")
                    .AppendTo(MenuWidget)
                    .Html(Constants.DownMark)
                    .Height(el.GetOuterHeight())
                    ;

                // Element hiddin behind list used to capture focus outline and hide it
                jQueryObject focs = jQuery.FromHtml("<span class='DropMenuFocus' style='display:none;color:transparent;background:transparent;position:absolute;right:10px' tabindex='999'/>")
                    .AppendTo(MenuWidget)
                    .Html(Constants.DownMark)
                    ;
                List = jQuery.FromHtml("<ul class='DropMenu' style='display:none'/>")
                    .AppendTo(MenuWidget)
                    ;

                MenuWidget.InsertBefore(el)
                    ;

                FireButton
                    .Click(
                        delegate(jQueryEvent e)
                        {
                            e.PreventDefault();
                            if (!List.Is(":visible"))
                            {
                                int ht = MenuWidget.GetOuterHeight();
                                focs.CSS("top", (ht + 4) + "px").Show().Focus();
                                List.CSS("top", ht + "px").Show();
                                ArrowClick();
                            }
                        }
                    )
                    ;

                focs
                    .FocusOut(
                        delegate
                        {
                            new Await()
                                .AddDx(
                                    delegate
                                    {
                                        FireButton.Focus();
                                        focs.Hide();
                                        List.FadeOut(120);
                                        MenuHide();
                                    })
                                .Commit();
                        }
                    )
                    ;

                Unselectable(FireButton);
                Unselectable(focs);
            }
            else
            {
                if (nameList.Count == 0)
                {
                    priorList.Closest(".DropMenuWidget").Remove();
                    return;
                }
                List = priorList;
                List.Empty();
            }

            foreach (KeyValuePair<string, string> p in nameList)
            {
                jQueryObject item = jQuery.FromHtml("<li class='DropMenuItem'/>")
                    .AppendTo(List)
                    .Data("MenuData", p.Key)
                    .MouseDown(
                        delegate(jQueryEvent e)
                        {
                            // Click could be on <a> or <li> hence use CurrentTarget to get <li>
                            ClickItem = jQuery.FromElement(e.CurrentTarget);
                            string nd = (string) ClickItem.GetDataValue("MenuData");
                            handler(e, nd);
                            ItemClick();
                        }
                    )
                    ;
                jQuery.FromHtml("<span/>")
                    .AppendTo(item)
                    .Html(p.Value)
                    ;
            }
        }

        public virtual void ItemClick()
        {
        }

        public virtual void ArrowClick()
        {
        }

        public virtual void MenuHide()
        {
        }

        private static void Unselectable(jQueryObject el)
        {
            Element elem = el[0];
            Type.SetField(elem, "onselectstart", Script.Literal("function() { return false; }"));
            Type.SetField(elem.Style, "MozUserSelect", "none");
            Type.SetField(elem.Style, "KhtmlUserSelect", "none");
            Type.SetField(elem, "unselectable", "on");
        }

        public static Dictionary Listify(Dictionary dict, CompareCallback<object> sort, Action<Dictionary, object> format)
        {
            List<object> mg = new List<object>();
            foreach (string k in dict.Keys)
            {
                mg.Add(dict[k]);
            }
            mg.Sort(sort);
            Dictionary d = new Dictionary();
            foreach (object o in mg)
            {
                format(d, o);
            }
            return d;
        }
    }
}